package cz.muni.fi.pa165.dundd.serviceImpl;

import cz.muni.fi.pa165.dundd.assembler.Assembler;
import cz.muni.fi.pa165.dundd.dao.HeroDAO;
import cz.muni.fi.pa165.dundd.dto.HeroDTO;
import cz.muni.fi.pa165.dundd.dto.HeroRoleDTO;
import cz.muni.fi.pa165.dundd.entity.Hero;
import cz.muni.fi.pa165.dundd.entity.HeroRole;
import cz.muni.fi.pa165.dundd.service.HeroService;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 * @author xszanto1 <ardos@mail.muni.cz>, Šimon Demočko
 */
@Service
@Transactional
public class HeroServiceImpl implements HeroService, UserDetailsService {

    @Autowired
    private HeroDAO heroDAO;

    public void setHeroDAO(HeroDAO heroDAO) {
        this.heroDAO = heroDAO;
    }

    @Override
    public void createHero(HeroDTO hero) {
        heroDAO.createHero(Assembler.heroDtoToEntity(hero));
    }

    @Override
    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    public HeroDTO retrieveHero(Long id) {
        return Assembler.heroEntityToDTO(heroDAO.retrieveHero(id));
    }

    @Override
    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    public List<HeroDTO> retrieveAllHeroes() {
        List<Hero> heroList = heroDAO.retrieveAllHeroes();
        List<HeroDTO> heroDTOList = new ArrayList<>();
        for (Hero hero : heroList) {
            heroDTOList.add(Assembler.heroEntityToDTO(hero));
        }
        return heroDTOList;
    }

    @Override
    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    public void updateHero(HeroDTO hero) {
        heroDAO.updateHero(Assembler.heroDtoToEntity(hero));
    }

    @Override
    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    public void deleteHero(HeroDTO hero) {
        heroDAO.deleteHero(Assembler.heroDtoToEntity(hero));
    }

    @Override
    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    public List<HeroRoleDTO> retrieveRolesOfHero(HeroDTO hero) {
        Hero retrievedHero = heroDAO.retrieveHero(hero.getId());
        List<HeroRole> retrRoles = retrievedHero.getRoles();

        List<HeroRoleDTO> result = new ArrayList<>();
        for (HeroRole heroRole : retrRoles) {
            result.add(Assembler.heroRoleEntityToDTO(heroRole));
        }
        return result;
    }

    @Override
    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    public void addRoleToHero(HeroDTO hero, HeroRoleDTO role) {
        Hero retrievedHero = heroDAO.retrieveHero(hero.getId());
        retrievedHero.addRole(Assembler.heroRoleDtoToEntity(role));
        heroDAO.updateHero(retrievedHero);
    }

    @Override
    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    public void deleteRoleOfHero(HeroDTO hero, HeroRoleDTO role) {
        Hero retrievedHero = heroDAO.retrieveHero(hero.getId());
        retrievedHero.removeRole(Assembler.heroRoleDtoToEntity(role));
        heroDAO.updateHero(retrievedHero);
    }

//    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
//    @Transactional
//    @Override
//    public HeroDTO retrieveHeroByName(String name) {
//        try {
//            HeroDTO heroDto = Assembler.heroEntityToDTO(heroDAO.retrieveHero(name));
//            return heroDto;
//        } catch (Exception ex) {
//            return null;
//        }
//    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (username == null || username.isEmpty()) {
            return null;
        }

        HeroDTO dto = retrieveHero(username);
        Hero hero = Assembler.heroDtoToEntity(dto);
        if (hero == null) {
            return null;
        }
        GrantedAuthority grantedAuth = new HeroGrantedAuthority(hero.getAuthority());
        HeroLoginDetails returnedHeroLD
                = new HeroLoginDetails(hero.getId(), hero.getName(), hero.getPassword(),
                        new GrantedAuthority[]{grantedAuth});
        return returnedHeroLD;
    }

    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    private HeroDTO retrieveHero(String username) {
        try {
            HeroDTO heroDto = Assembler.heroEntityToDTO(heroDAO.retrieveHero(username));
            return heroDto;
        } catch (Exception ex) {
            return null;
        }
    }
}
